//----------------------------------------------------
// 智能指针的实现
// auto_ptr、unique_ptr、shared_ptr、weak_ptr实现
//----------------------------------------------------
#include <iostream>


namespace ymbxWidget
{
    // auto_ptr

    // unique_ptr
    // 强调对资源的独占性，一个对象只能有一个指针，而且不能拷贝构造和赋值，但支持移动构造和移动赋值

    template <class T,class Deleter>
    class unique_ptr
    {
    public:
        unique_ptr(T* t):_t(t){}
        T *get()
        {
            return _t;
        }
        void reset(T* t){
            if(_t){
                _del(_t);
            }
            _t=t;
        }
        T operator*()
        {
            return *_t;
        }
        T *operator->()
        {
            return _t;
        }
        // 只是释放他的管理权，然后返还指针
        T* release(){
            T* tmp;
            if(_t){
                tmp=_t;
                _t=nullptr;
            }
            return tmp;
        }
        ~unique_ptr(){
            if(_t){
                _del(_t);
            }
        }
        unique_ptr(const unique_ptr<T> &t) = delete;
        unique_ptr<T> &operator=(const unique_ptr<T> &t) = delete;

    private:
        T *_t;
        Deleter _del;
    };

    // shared_ptr
    //  共享指针强调对资源的共享，当指针的引用计数变为0时，会调用析构函数释放该指针
    //  线程安全问题：shared_ptr内部的引用计数是线程安全的，但指向的对象不一定是线程安全的，需要用户自定义
    
    // 删除器，对于malloc出来的空间释放时需要自定义删除器，具体是通过仿函数重载operator()来实现
        // 也可以直接传递lambda表达式作为删除器：unique_ptr中需要显式传入类型；shared_ptr中可以自动推导类型，不需要显式传入
    template <class T,class Deleter>
    class shared_ptr
    {
    public:
        shared_ptr(T* t):_t(t){
            _shared_cnt=new int(1);
            _weak_cnt=new int(0);
        }
        shared_ptr(const shared_ptr<T> &t)
        {
            _t=t._t;
            _shared_cnt=t._shared_cnt;
            _weak_cnt=t._weak_cnt;
            (*_shared_cnt)++;
        }
        shared_ptr<T> &operator=(const shared_ptr<T> &t)
        {
            if (this!=&t)
            {
                if (_t != nullptr)
                {
                    (*_shared_cnt)--;
                    if (*_shared_cnt == 0)
                    {
                        _del(_t);
                    }
                }
                _t = t._t;
                _shared_cnt = t._shared_cnt;
                _weak_cnt = t._weak_cnt;
                (*_shared_cnt)++;
            }
            return *this;
        }
        int use_count()
        {
            return *_shared_cnt;
        }
        T *get()
        {
            return _t;
        }
        T operator*()
        {
            return *_t;
        }
        T *operator->()
        {
            return _t;
        }
        void reset(T* t)
        {
            if(_t){
                _del(_t);
            }
            if(t){
                _t = t;
            *_shared_cnt=1;
            *_weak_cnt=0;
            }else{
                _t = t;
            *_shared_cnt=0;
            *_weak_cnt=0;
            }
            
        }
        ~shared_ptr(){
            if(*_shared_cnt==0){
                _del(_t);
                delete _shared_cnt;
                delete _weak_cnt;
            }
        }
    private:
        T *_t;
        int *_shared_cnt;
        int *_weak_cnt;
        Deleter _del;
    };

    // 循环引用：当一个node节点中有两个shared_ptr一个指向prev，一个指向next，程序退出时两个引用计数都不会减为1，会造成内存泄漏
    // weak_ptr 为解决shared_ptr的循环引用问题只需要将节点变成weak_ptr即可

}



int main(){
    // shared_ptr测试

    // ymbxWidget::shared_ptr<int> sp(new int(1));
    // std::cout<<sp.count()<<std::endl;
    // ymbxWidget::shared_ptr<int> spp(sp);
    // std::cout<<"sp count:"<<sp.count()<<std::endl;
    // std::cout<<"spp count:"<<spp.count()<<std::endl;
    // ymbxWidget::shared_ptr<int> sp3(new int(0));
    // std::cout<<"sp count:"<<sp.count()<<std::endl;
    // std::cout<<"sp3 count:"<<sp3.count()<<std::endl;
    // int* oldsp3=sp3.get();
    // sp3=sp;
    // std::cout<<sp.count()<<std::endl;
    // std::cout<<"oldsp3 value:"<<*oldsp3<<std::endl;

    // int* spg=sp.get();
    // int* sp3g=sp3.get();
    // std::cout<<"sp value:"<<*spg<<std::endl;
    // std::cout<<"sp3 value:"<<*sp3g<<std::endl;
    // sp.reset();
    // std::cout<<"sp count:"<<sp.count()<<std::endl;

    // unique_ptr测试
    ymbxWidget::unique_ptr<int> up(new int(1));
    // std::cout<<"up value:"<<*up<<std::endl;
    // ymbxWidget::unique_ptr<int> upp(up);
    // ymbxWidget::unique_ptr<int> up2(new int(0));
    // std::cout<<"up2 value:"<<*up2<<std::endl;
    // up2=up;
    ymbxWidget::unique_ptr<int> up3(std::move(up));
    std::cout<<"up value:"<<*up<<std::endl;
    std::cout<<"up3 value:"<<*up3<<std::endl;

    return 0;
}